/*
* Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const { Buffer } = require('buffer');
window.Buffer = Buffer;

const BN = require('./bn');
window.BN = BN;

const _encoder = require("./base_serialize")
const _decoder = require("./base_deserialize")

// bool
// byte
// char
// duration
// float32
// float64
// int16
// int32
// int64
// int8
// string
// time
// uint16
// uint32
// uint64
// uint8

class PackageTool {
    static put = _encoder;
    static putArray = _encoder.Array;
    static get = _decoder;
    static getArray = _decoder.Array;

    constructor(data = null, size = 4096) {
        if (data != null) {
            this.buffer = Buffer.from(data);
        } else {
            this.buffer = Buffer.alloc(size);
        }
        this.offset = [0];
    }
    clear() {
        this.offset = [0];
    }
    put_bool(value) { this.offset[0] = _encoder.bool(value, this.buffer, this.offset[0]); }
    put_byte(value) { this.offset[0] = _encoder.byte(value, this.buffer, this.offset[0]); }
    put_char(value) { this.offset[0] = _encoder.char(value.charCodeAt(0), this.buffer, this.offset[0]); }
    put_duration(value) { this.offset[0] = _encoder.duration(value, this.buffer, this.offset[0]); }
    put_float32(value) { this.offset[0] = _encoder.float32(value, this.buffer, this.offset[0]); }
    put_float64(value) { this.offset[0] = _encoder.float64(value, this.buffer, this.offset[0]); }
    put_int16(value) { this.offset[0] = _encoder.int16(value, this.buffer, this.offset[0]); }
    put_int32(value) { this.offset[0] = _encoder.int32(value, this.buffer, this.offset[0]); }
    put_int64(value) { this.offset[0] = _encoder.int64(value, this.buffer, this.offset[0]); }
    put_int8(value) { this.offset[0] = _encoder.int8(value, this.buffer, this.offset[0]); }
    put_string(value) { this.offset[0] = _encoder.string(value, this.buffer, this.offset[0]); }
    put_time(value) { this.offset[0] = _encoder.time(value, this.buffer, this.offset[0]); }
    put_uint16(value) { this.offset[0] = _encoder.uint16(value, this.buffer, this.offset[0]); }
    put_uint32(value) { this.offset[0] = _encoder.uint32(value, this.buffer, this.offset[0]); }
    put_uint64(value) { this.offset[0] = _encoder.uint64(value, this.buffer, this.offset[0]); }
    put_uint8(value) { this.offset[0] = _encoder.uint8(value, this.buffer, this.offset[0]); }

    put_bool_array(value) { this.offset[0] = _encoder.Array.bool(value, this.buffer, this.offset[0]); }
    put_byte_array(value) { this.offset[0] = _encoder.Array.byte(value, this.buffer, this.offset[0]); }
    put_char_array(value) { this.offset[0] = _encoder.Array.char(value.map(code => code.charCodeAt(0)), this.buffer, this.offset[0]); }
    put_duration_array(value) { this.offset[0] = _encoder.Array.duration(value, this.buffer, this.offset[0]); }
    put_float32_array(value) { this.offset[0] = _encoder.Array.float32(value, this.buffer, this.offset[0]); }
    put_float64_array(value) { this.offset[0] = _encoder.Array.float64(value, this.buffer, this.offset[0]); }
    put_int16_array(value) { this.offset[0] = _encoder.Array.int16(value, this.buffer, this.offset[0]); }
    put_int32_array(value) { this.offset[0] = _encoder.Array.int32(value, this.buffer, this.offset[0]); }
    put_int64_array(value) { this.offset[0] = _encoder.Array.int64(value, this.buffer, this.offset[0]); }
    put_int8_array(value) { this.offset[0] = _encoder.Array.int8(value, this.buffer, this.offset[0]); }
    put_string_array(value) { this.offset[0] = _encoder.Array.string(value, this.buffer, this.offset[0]); }
    put_time_array(value) { this.offset[0] = _encoder.Array.time(value, this.buffer, this.offset[0]); }
    put_uint16_array(value) { this.offset[0] = _encoder.Array.uint16(value, this.buffer, this.offset[0]); }
    put_uint32_array(value) { this.offset[0] = _encoder.Array.uint32(value, this.buffer, this.offset[0]); }
    put_uint64_array(value) { this.offset[0] = _encoder.Array.uint64(value, this.buffer, this.offset[0]); }
    put_uint8_array(value) { this.offset[0] = _encoder.Array.uint8(value, this.buffer, this.offset[0]); }

    get_bool() { return _decoder.bool(this.buffer, this.offset); }
    get_byte() { return _decoder.byte(this.buffer, this.offset); }
    get_char() { return String.fromCharCode(_decoder.char(this.buffer, this.offset)); }
    get_duration() { return _decoder.duration(this.buffer, this.offset); }
    get_float32() { return _decoder.float32(this.buffer, this.offset); }
    get_float64() { return _decoder.float64(this.buffer, this.offset); }
    get_int16() { return _decoder.int16(this.buffer, this.offset); }
    get_int32() { return _decoder.int32(this.buffer, this.offset); }
    get_int64() { return _decoder.int64(this.buffer, this.offset); }
    get_int8() { return _decoder.int8(this.buffer, this.offset); }
    get_string() { return _decoder.string(this.buffer, this.offset); }
    get_time() { return _decoder.time(this.buffer, this.offset); }
    get_uint16() { return _decoder.uint16(this.buffer, this.offset); }
    get_uint32() { return _decoder.uint32(this.buffer, this.offset); }
    get_uint64() { return _decoder.uint64(this.buffer, this.offset); }
    get_uint8() { return _decoder.uint8(this.buffer, this.offset); }

    get_bool_array() { return _decoder.Array.bool(this.buffer, this.offset); }
    get_byte_array() { return _decoder.Array.byte(this.buffer, this.offset); }
    get_char_array() { return Array.from(_decoder.Array.char(this.buffer, this.offset)).map(code => String.fromCharCode(code)); }
    get_duration_array() { return _decoder.Array.duration(this.buffer, this.offset); }
    get_float32_array() { return _decoder.Array.float32(this.buffer, this.offset); }
    get_float64_array() { return _decoder.Array.float64(this.buffer, this.offset); }
    get_int16_array() { return _decoder.Array.int16(this.buffer, this.offset); }
    get_int32_array() { return _decoder.Array.int32(this.buffer, this.offset); }
    get_int64_array() { return _decoder.Array.int64(this.buffer, this.offset); }
    get_int8_array() { return _decoder.Array.int8(this.buffer, this.offset); }
    get_string_array() { return _decoder.Array.string(this.buffer, this.offset); }
    get_time_array() { return _decoder.Array.time(this.buffer, this.offset); }
    get_uint16_array() { return _decoder.Array.uint16(this.buffer, this.offset); }
    get_uint32_array() { return _decoder.Array.uint32(this.buffer, this.offset); }
    get_uint64_array() { return _decoder.Array.uint64(this.buffer, this.offset); }
    get_uint8_array() {
        // let arr = _decoder.Array.uint8(this.buffer, this.offset);
        // return pako.inflate(arr);
        return _decoder.Array.uint8(this.buffer, this.offset);
    }

    test() {
        this.put_bool(true);
        this.put_byte(123);
        this.put_char('a');
        this.put_duration({ nsecs: 123456789, secs: 1234567890 });
        this.put_float32(3.1415926);
        this.put_float64(3.1415926);
        this.put_int16(-32768);
        this.put_int32(-2147483648);
        this.put_int64(new BN('-9223372036854775808'));
        this.put_int8(-128);
        this.put_string("Hello, world!");
        this.put_time({ nsecs: 123456789, secs: 1234567890 });
        this.put_uint16(65535);
        this.put_uint32(4294967295);
        this.put_uint64(new BN('18446744073709551615'));
        this.put_uint8(255);

        this.put_bool_array([true, false, true]);
        this.put_byte_array([1, 2, 3]);
        this.put_char_array(['a', 'b', 'c']);
        this.put_duration_array([{ nsecs: 1, secs: 2 }, { nsecs: 3, secs: 4 }]);
        this.put_float32_array([3.1415926, 2.7182818]);
        this.put_float64_array([3.1415926, 2.7182818]);
        this.put_int16_array([-32768, -32767, 32767]);
        this.put_int32_array([-2147483648, -2147483647, 2147483647]);
        this.put_int64_array([new BN('-9223372036854775808'), new BN('-9223372036854775807'), new BN('9223372036854775807')]);
        this.put_int8_array([-128, -127, 127]);
        this.put_string_array(["Hello, world!", "你好，世界！"]);
        this.put_time_array([{ nsecs: 5, secs: 6 }, { nsecs: 7, secs: 8 }]);
        this.put_uint16_array([65535, 65534, 0]);
        this.put_uint32_array([4294967295, 4294967294, 0]);
        this.put_uint64_array([new BN('18446744073709551615'), new BN('18446744073709551614'), new BN('0')]);
        this.put_uint8_array([255, 254, 0]);
        //打印this.buffer
        let ss = "["
        for (let i = 0; i < this.offset[0]; i++) {
            ss += this.buffer[i].toString(10) + ","
        }
        console.log(this.offset[0], ss + "]");
        this.offset[0] = 0;
        //读取后和写入的数据对比
        let t;
        t = this.get_bool();
        if (t === true) { console.log("bool: ok"); } else { console.log("bool: error"); }
        t = this.get_byte();
        if (t === 123) { console.log("byte: ok"); } else { console.log("byte: error"); }
        t = this.get_char();
        if (t === 'a') { console.log("char: ok"); } else { console.log("char: error"); }
        t = this.get_duration();
        if (t.nsecs === 123456789 && t.secs === 1234567890) { console.log("duration: ok"); } else { console.log("duration: error"); }
        t = this.get_float32();
        if (t == 3.1415926) { console.log("float32: ok"); } else { console.log("float32: error :", 3.1415926, t); }
        t = this.get_float64();
        if (t === 3.1415926) { console.log("float64: ok"); } else { console.log("float64: error"); }
        t = this.get_int16();
        if (t === -32768) { console.log("int16: ok"); } else { console.log("int16: error"); }
        t = this.get_int32();
        if (t === -2147483648) { console.log("int32: ok"); } else { console.log("int32: error"); }
        t = this.get_int64();
        if (t.toString() === '-9223372036854775808') { console.log("int64: ok"); } else { console.log("int64: error"); }
        t = this.get_int8();
        if (t === -128) { console.log("int8: ok"); } else { console.log("int8: error"); }
        t = this.get_string();
        if (t === "Hello, world!") { console.log("string: ok"); } else { console.log("string: error"); }
        t = this.get_time();
        if (t.nsecs === 123456789 && t.secs === 1234567890) { console.log("time: ok"); } else { console.log("time: error"); }
        t = this.get_uint16();
        if (t === 65535) { console.log("uint16: ok"); } else { console.log("uint16: error"); }
        t = this.get_uint32();
        if (t === 4294967295) { console.log("uint32: ok"); } else { console.log("uint32: error"); }
        t = this.get_uint64();
        if (t.toString() === '18446744073709551615') { console.log("uint64: ok"); } else { console.log("uint64: error"); }
        t = this.get_uint8();
        if (t === 255) { console.log("uint8: ok"); } else { console.log("uint8: error"); }

        t = this.get_bool_array();
        if (t[0] === true && t[1] === false && t[2] === true) { console.log("bool_array: ok"); } else { console.log("bool_array: error"); }
        t = this.get_byte_array();
        if (t[0] === 1 && t[1] === 2 && t[2] === 3) { console.log("byte_array: ok"); } else { console.log("byte_array: error"); }
        t = this.get_char_array()
        if (t[0] === 'a' && t[1] === 'b' && t[2] === 'c') { console.log("char_array: ok"); } else { console.log("char_array: error"); }
        t = this.get_duration_array();
        if (t[0].nsecs === 1 && t[0].secs === 2 && t[1].nsecs === 3 && t[1].secs === 4) { console.log("duration_array: ok"); } else { console.log("duration_array: error"); }
        t = this.get_float32_array();
        if (t[0] === 3.1415926 && t[1] === 2.7182818) { console.log("float32_array: ok"); } else { console.log("float32_array: error :", 3.1415926, t[0], ",", 2.7182818, t[1]); }
        t = this.get_float64_array();
        if (t[0] === 3.1415926 && t[1] === 2.7182818) { console.log("float64_array: ok"); } else { console.log("float64_array: error"); }
        t = this.get_int16_array();
        if (t[0] === -32768 && t[1] === -32767 && t[2] === 32767) { console.log("int16_array: ok"); } else { console.log("int16_array: error"); }
        t = this.get_int32_array();
        if (t[0] === -2147483648 && t[1] === -2147483647 && t[2] === 2147483647) { console.log("int32_array: ok"); } else { console.log("int32_array: error"); }
        t = this.get_int64_array();
        if (t[0].toString() === '-9223372036854775808' && t[1].toString() === '-9223372036854775807' && t[2].toString() === '9223372036854775807') { console.log("int64_array: ok"); } else { console.log("int64_array: error"); }
        t = this.get_int8_array();
        if (t[0] === -128 && t[1] === -127 && t[2] === 127) { console.log("int8_array: ok"); } else { console.log("int8_array: error"); }
        t = this.get_string_array();
        if (t[0] === "Hello, world!" && t[1] === "你好，世界！") { console.log("string_array: ok"); } else { console.log("string_array: error"); }
        t = this.get_time_array();
        if (t[0].nsecs === 5 && t[0].secs === 6 && t[1].nsecs === 7 && t[1].secs === 8) { console.log("time_array: ok"); } else { console.log("time_array: error"); }
        t = this.get_uint16_array();
        if (t[0] === 65535 && t[1] === 65534 && t[2] === 0) { console.log("uint16_array: ok"); } else { console.log("uint16_array: error"); }
        t = this.get_uint32_array();
        if (t[0] === 4294967295 && t[1] === 4294967294 && t[2] === 0) { console.log("uint32_array: ok"); } else { console.log("uint32_array: error"); }
        t = this.get_uint64_array();
        if (t[0].toString() === '18446744073709551615' && t[1].toString() === '18446744073709551614' && t[2].toString() === '0') { console.log("uint64_array: ok"); } else { console.log("uint64_array: error"); }
        t = this.get_uint8_array();
        if (t[0] === 255 && t[1] === 254 && t[2] === 0) { console.log("uint8_array: ok"); } else { console.log("uint8_array: error"); }
    }
}

window.g_pt = new PackageTool(null, 1024 * 1024 * 10);

module.exports = {
    PackageTool
}